#include "myQueue.h"
#include "initFunc.h"
#include "load_config.h"
#include "serverFucs.h"
#include "cmdParser.h"
#include "utils.h"
/*
   用于父进程与子进程通信的管道
   当父进程收到退出信号时，通知子进程，让子进程的线程有序退出，然后再依次退出
   */
int pipeFd[2];

// 通过异步拉起同步的方式来完成线程池所有功能
int main(int argc, char const *argv[])
{

    int ret = pipe(pipeFd);
    ERROR_CHECK(ret, -1, "pipe");
    pid_t pid = fork();
    if (pid != 0)
    {
        // 父进程执行逻辑
        // 关闭读端
        close(pipeFd[0]);
        signal(SIGINT, EXIT);
        wait(NULL);
        printf("子<-->父进程退出...\n");
        close(pipeFd[1]);
    }
    else
    {
        // 脱离前台进程组
        setpgid(0, 0);
        status_st threadControl;
        initQueue(&threadControl);


        // pthread_t threadIds[THREADNUM];// 没用
        initThreadControl(&threadControl, threadControl.thread_id);
        // initThreadControl(&threadControl,THREADNUM);
        // 初始化listenFd、bind、listen
        int listenFd;
        char ip[100] = {0};
        getparameter("ip", ip); // 获得ip
        char port[10] = {0};
        getparameter("port", port); // 获得端口

        // 初始化socket连接,bind绑定,linsten监听
        initSockBindListen(&listenFd, ip, atoi(port));
        // 创建epoll监听fd
        int epollFd = epoll_create(1);
        if (epollFd == -1)
        {
            perror("epoll");
            exit(-1);
        }
        // 增加监听对象
        addEpollObj(epollFd, listenFd);  // 监听新连接
        addEpollObj(epollFd, pipeFd[0]); // 监听管道退出信号
        while (1)
        {
            // 创建用户态下的就绪队列
            struct epoll_event events[10];
            int readyNum = epoll_wait(epollFd, events, 10, -1);
            char sendBuf[1024] = {0};
            char recvBuf[1024] = {0};
            for (int i = 0; i < readyNum; i++)
            {

                int curFd = events[i].data.fd;
                if (curFd == listenFd)
                {
                    int socketFd;
                    getSocktLink(curFd, &socketFd);

                    // 用户名的密码验证
                    memset(recvBuf, 0, sizeof(recvBuf));
                    int count = recv(socketFd, recvBuf, sizeof(recvBuf), 0);
                    if (count == 0)
                        break;
                    char uname[20] = { 0 };
                    bool isOk = judgeUserPwd(recvBuf,uname);
                    // 响应客户端【密码认证】
                    if (isOk == false) // 验证失败
                    {
                        int ret = 0;
                        memset(sendBuf, 0, sizeof(sendBuf));
                        send(socketFd, &ret, 4, 0);
                        // 关闭客户端连接
                        close(socketFd);
                        continue;
                    }
                    else // 验证成功
                    {
                        int ret = 1;
                        memset(sendBuf, 0, sizeof(sendBuf));
                        send(socketFd, &ret, 4, 0);
                    }

                    /*
                        下面是密码验证成功后，开始进行入队操作
                    */

                    // 创建服务器工作的文件夹
                    char actualUserName[10] = {0}; // 自己虚拟机真实的用户名，比如我的是tk
                    getlogin_r(actualUserName, sizeof(actualUserName));
                    // 拼接服务端的工作路径
                    char serverPath[20] = {0};
                    sprintf(serverPath, "/home/%s", actualUserName);
                    creat_folder(serverPath);

                    // printf("125:serverPath:%s\n", serverPath);
                    // 创建用户根路径文件夹
                    char userWorkPath[1024] = {0};
                    sprintf(userWorkPath, "%s/%s", serverPath, uname);
                    creat_folder(userWorkPath);

                    // 加锁入队列
                    pthread_mutex_lock(&threadControl.mutex);
                    // 判断队列是否满了
                    if (isFull((&threadControl.q), THREADNUM) == true)
                    {
                        // 等待队列里位置了，唤醒队列
                        pthread_cond_wait(&threadControl.cond, &threadControl.mutex);
                    }
                    // 入队列
                    // 构建结构体【用户名、当前路径、连接客户端的socketFd、】
                    qNode_st *node = calloc(1, sizeof(qNode_st));
                    memcpy(node->curPath, "/", 1); // 客户端当前路径
                    memcpy(node->username,uname,strlen(uname)); // 客户端用户名
                    node->fd = socketFd; // 连接客户端的socketFd
                    node->aliveStatus = 1; // 存活状态
                    memcpy(node->serverPath,serverPath,strlen(serverPath));
                    // 入队列
                    inQueue(&threadControl.q, node);
                    threadControl.q.size += 1;
                    // 广播通知子线程 --> 改为通知一个子进程
                    pthread_cond_signal(&threadControl.cond);
                    // 解锁
                    pthread_mutex_unlock(&threadControl.mutex);
                    continue;
                }
                else
                {
                    // 收到管道信号
                    int flag;
                    read(pipeFd[0], &flag, sizeof(int));
                    if (flag == -1)
                    {
                        // 修改子进程退出标志位
                        threadControl.exitFlag = -1;
                        for (int j = 0; j < threadControl.threadNum; j++)
                        {
                            // 等待子进程退出
                            pthread_cond_broadcast(&threadControl.cond);
                            pthread_join(threadControl.thread_id[j], NULL);
                            printf("子线程退出+1\n");
                            // 销毁锁
                            pthread_mutex_destroy(&threadControl.mutex);
                        }
                        // 释放队列
                        destoryQueue(&threadControl.q);
                        // 销毁条件变量
                        pthread_cond_destroy(&threadControl.cond);
                        // 退出
                        exit(-1);
                    }
                }
            }
        }
        return 0;
    }
}
void EXIT(int sig_no)
{
    printf("收到退出信号:%d\n", sig_no);
    int exitFlag = -1;
    write(pipeFd[1], &exitFlag, sizeof(int));
}
